package guida.ccf.gzuexaminesystem.utils;

import guida.ccf.gzuexaminesystem.entity.minio.DeleteFileDto;
import guida.ccf.gzuexaminesystem.entity.minio.SaveFileDto;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;

@Component
public class MinioUtil {

    @Autowired
    private MinioClient minioClient;


    /**
     * 保存多个文件
     *
     * @return true 成功, false 失败
     */
    public boolean saveFileAll(List<SaveFileDto> list) {

        for (SaveFileDto saveFileDto : list) {

            String bucket = saveFileDto.getBucket();
            String folder = saveFileDto.getFolder();
            MultipartFile file = saveFileDto.getFile();
            String md5 = saveFileDto.getMd5();

            boolean flag = saveFile(bucket, folder, file, md5);
            if (!flag) {
                return false;
            }
        }

        return true;
    }

    /**
     * 单文件上传
     *
     * @param bucket 桶
     * @param folder 文件夹
     * @param md5    原始文件的md5值
     * @return true 成功, false 失败
     */
    public boolean saveFile(String bucket, String folder, MultipartFile file, String md5) {
        try {
            /*
             * 判断md5验证文件完整性
             */
            String fileMd5 = DigestUtils.md5Hex(file.getInputStream());
            if(!fileMd5.equals(md5)){
                return false;
            }

            InputStream inputStream = file.getInputStream();
            long size = file.getSize();
            String originalFilename = file.getOriginalFilename();


            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(bucket)
                    .object(folder + originalFilename)
                    .stream(inputStream, size, -1) // -1表示不分片存储
                    .build();

            minioClient.putObject(args);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    /**
     * 传入相关参数获得文件
     *
     * @param bucket   桶
     * @param folder   文件夹
     * @param fileName 文件名
     * @param response 响应
     * @param md5      原始文件的md5值
     * @return true为文件完整 false为文件损坏或者网络波动
     */
    public boolean getFile(String bucket, String folder, String fileName, String md5, HttpServletResponse response) {
        //文件=文件夹+文件名
        String file = folder + fileName;

        try {
            //标记重新获取文件的次数，3次则可能网络波动或者文件已损坏
            int count = 0;


            File tempFile = null;
            byte[] buffer = new byte[0];
            int length;

            while (true) {

                if (count == 3) {//3次则可能网络波动或者文件已损坏
                    return false;
                }

                count++;

                GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucket).object(file).build();
                FilterInputStream inputStream = minioClient.getObject(getObjectArgs);
                // 设置响应头信息
                String contentType = "application/pdf"; // 根据文件类型设置合适的Content-Type
                String encodedFilename = URLEncoder.encode(fileName, "UTF-8");
                response.setContentType(contentType);
                response.setHeader("Content-Disposition", "attachment; filename=" + encodedFilename);


                /*
                 * 需要临时文件来计算文件的md5值
                 */
                // 创建临时文件
                tempFile = File.createTempFile("temp", ".zip");
                FileOutputStream fileOutputStream = new FileOutputStream(tempFile);


                // 将输入流中的内容保存到临时文件中
                buffer = new byte[1024];
                while ((length = inputStream.read(buffer)) != -1) {
                    fileOutputStream.write(buffer, 0, length);
                }

                // 关闭输入流和输出流
                inputStream.close();
                fileOutputStream.close();

                // 计算MD5值
                String fileMd5 = DigestUtils.md5Hex(new FileInputStream(tempFile));


                break;
//                if (fileMd5.equals(md5)) {//md5相同则表示获得完整文件
//                    break;
//                }
            }

            // 将临时文件内容写入响应输出流
            FileInputStream fileInputStream = new FileInputStream(tempFile);
            OutputStream outputStream = response.getOutputStream();
            while ((length = fileInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }

            // 关闭输入流和输出流
            fileInputStream.close();
            outputStream.close();

            // 删除临时文件
           tempFile.delete();


        } catch (Exception e) {
            // 处理异常
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 删除一些文件
     * @param list 文件集合
     * @return true 成功, false 失败
     */
    public boolean deleteFileAll(List<DeleteFileDto> list) {

        for (DeleteFileDto deleteFileDto : list) {

            String bucket = deleteFileDto.getBucket();
            String folder = deleteFileDto.getFolder();
            String fileName = deleteFileDto.getFileName();

            boolean flag = deleteFile(bucket, folder, fileName);
            if (!flag) {
                return false;
            }
        }

        return true;
    }

    /**
     * 删除单个文件
     *
     * @param bucket   桶
     * @param folder   文件夹
     * @param fileName 文件名
     * @return true 成功, false 失败
     */
    public boolean deleteFile(String bucket, String folder, String fileName) {
        String file = folder + fileName;

        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder().bucket(bucket).object(file).build());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
